#ifndef inputmanager_hpp
#define inputmanager_hpp

#include <lock_manager/lock_manager.hpp>
#include <list>
#include <boost/thread.hpp>
#include <boost/circular_buffer.hpp>
#include <utils/mime_common.hpp>


/*
 * Event types
 */
#define EV_KEY			    0x01 
//...
#define EV_TOUCH		    0x06
//...
#define EV_Fingermodules	0x08



/** dev type **/
#define magic_str   " "
#define all_inputdev_type           "all-inputdev"
#define key_inputdev_type           "keyboard-inputdev"
#define fingermodule_inputdev_type  "fingermodule-inputdev"



// Encode : GB2312

struct input_event {
	unsigned short type;
	unsigned short code;
	unsigned int  value;
};

/** max input type 32*/

enum input_type {
    INPUT_SECURITY_KEY                  = (1<<0), 

    INPUT_PASSWORD                      = (1<<1),

            //INPUT_RFID                          = (1<<2),
            //INPUT_FINGERPRINT                   = (1<<3),
            //INPUT_FACE_ID                       = (1<<4),
            //INPUT_BLUETOOTH                     = (1<<5),

    INPUT_KEY                           = (1<<6), 

    INPUT_BATTERY                       = (1<<7),
            //INPUT_WIFI                          = (1<<8),

    INPUT_TOUCH                         = (1<<9),

    INPUT_TGCamera                      = (1<<10),
    
            //INPUT_TEST_RFID                     = (1<<15),
    INPUT_ALL_TYPE                      = (0xFFFF),
    INPUT_MANAGER                       = (0xFFFF),
    INPUT_NONE_TYPE                     = (0x0000),
};



#define combine_execption_info(id, detail)      (id<<24 | detail)
#define get_execption_id_from_info(infoval)     (infoval>>24)
#define get_execption_detail_from_info(infoval) (infoval&0x0fff)

class c_indevval{
public:
	unsigned short type;
	unsigned short code;
	unsigned short  value;

    unsigned int execption_info;
};

enum input_curfunc_done{
    curfunc_init = 0,
    curfuncdone = 1,     // 当前功能已经结束：例如，注册功能已结束，就是说注册所需的两步骤(第一次和第二次)已经完成了。
    curfuncnotdone,      // 当前功能未结束 
};


void clear_input_dev_param(input_dev_param* obj);


class input_dev_param {

public:
    input_dev_param();
    
    int mode; 
    int status;      // 标识结果成功还是失败 
    int detail;      // 标识结果失败时的具体原因  
    int isfuncdone;  // 判断当前功能是否结束的标志，注册需要两步骤。而验证只需要一步骤。

    /**下面俩参数对应的是 execption_info**/
    int execption_id;
    int cancel_reason; // 取消原因，手动操作的取消、系统功能切换而导致的自动取消、检测到错误操作而导致的取消


    int input_type;    
    int input_code;
    int input_value;


    char content[128];

#ifndef __cplusplus
/*
    pthread_mutex_t queue_lock;
    pthread_cond_t queue_ready;
    
    struct fifo_iterator *fifo_it;
*/
#else

    boost::condition_variable cond;	
    boost::mutex mutex; 			

    boost::circular_buffer<c_indevval> *queue;

#endif

    void *input_events;
};


/***输入管理类这个父类的初始化过程(的意义，说明
 * 所有的子类在工作前都需要一个统一的初始化过程。我现在就是将这个初始化过程放在了它们的父类的构造里去做，而且只做有且只有一次。
 * 举个例子： 输入管理类是父类，按键、鼠标是具体的子类，按键、鼠标、这些封装的子类设备都具有完备的功能。  
 * 例如，上报消息功能。
 * 具体的设备获取用户响应后将事件上报给输入管理类， 那么我这个输入管理类内部就得跑一个线程啊，用来接收上报的事件。   
 * 输入管理类这个父类的初始化过程，就包含了 创建并运行一个事件接收线程 的操作。
 * 本质上说，这件事情是为了能和子类正常交互去创建必要的条件。  
 * **/
class inputmanager{

protected:
    // 子类被构造的时候会导致父类被构造，有些事情只能发生一次，例如状态初始化，只需要初始化一次即可，就不能直接暴露在父类的构造函数内，
    //也就是说，放在这里会受子类的变化，代码执行次数是不稳定的。要在父类的构造函数内，需要做些限制。
    inputmanager(); // 可以在父类的构造函数内使用单例模式。让创建线程这种事情，全都在单例类去做掉。 
                    //经过这样改善，会使得阅读我代码的人可以更好地理解我的用意。别扭的感觉会完全消失。

public:

    static inputmanager* get_inputmanager();

    static inputmanager* pinputmanager_instance;

    virtual ~inputmanager();


    // 采用观察者模式 作为被观察者 

    void attach_event_listener(abstract_state_manager_isalso_listener*listener);
    void detach_event_listener(abstract_state_manager_isalso_listener*listener);

    void setState(input_dev_param* param);
    input_dev_param* getstate();
    void notify();
    
    input_dev_param param;

private:
    std::list<abstract_state_manager_isalso_listener*> observers_list;

public:

    char *name;
    int   input_type;
    void *private_data;


    /**使用父类子类的继承关系的主要原因是， 键盘、指纹模块这种，的确是输入类设备，所以需要由输入管理类来进行管理。
     * 输入管理类有一个虚的注册方法，键盘就负责实现。其他的具体的实际的待扩展的输入类设备，也都可以继承之，选择性实现自己的方法。
     * 配合简单工厂模式，为上层提供统一的接口以供调用不同设备平台的功能方法。
     * （以注册方法为例： 按键有按键的注册方法，就是按数字。指纹模块注册方法，就是放下手指。 不同设备平台有不同的注册方法。）
     * 
     * **/
    /* 采用简单工厂模式  这里的输入管理类 相当于 产品抽象类 */
    virtual int suspend(void);
    virtual int resume(void);

    virtual int enroll( input_dev_param *param);
    virtual int cancel_enroll( input_dev_param *param);

    virtual int authenticate( input_dev_param *param);
    virtual int cancel_authenticate( input_dev_param *param);
    
    /*  暂不考虑实现  */
    virtual int delete_user( input_dev_param *param);
    virtual int cancel_delete_user( input_dev_param *param);   

    /* Admin or Usr is deleted by his ID */
    virtual int get_userid( input_dev_param *param);
    virtual int cancel_get_userid( input_dev_param *param);

    /* 向设备传递参数容器，使得设备功能的调用者，能够在设备功能执行后，通过该参数获得执行结果的反馈  */
    virtual int notify_param_handle( input_dev_param *param);

    /* 外部调用该接口给设备发送信号量或消息队列，解除设备内部的一种阻塞状态 ，在有些场景下有这种需求 */
    virtual int notify_resource_to_inputdev( input_dev_param *param);


};


enum e_inputmanager_cmd{
    e_input_cmd_enroll,
    e_input_cmd_auth,
    e_input_cmd_getid,
    e_input_cmd_notifystatus,
};


enum inputdev_function_mode{
    s_indev_func_notinit = 0,

    s_indev_func_enroll,
    s_indev_func_cancelenroll,

    s_indev_func_auth,
    s_indev_func_cancelauth,

    s_indev_func_delete_user,
    s_indev_func_canceldelete_user,

    s_indev_func_get_userid,
    s_indev_func_cancelget_userid,

};


// 设备状态类 
class input_dev_status{
public:
    int cur_function_mode;    // 设备当前所处的功能模式

    devfunc_notify* protect; //  设备当前所需要的能提供IPC保护机制的资源


};


enum input_dev_execption{
    input_no_ececption = 0,

    /* keyboard */ 
    input_execption_operation_irregular,  /*** 用户操作非法，而导致的功能取消 ***/
    
    input_execption_timeout,
};


enum input_cancelreason_datail{     
    detail_syste_auto_cancel = 6,  
    /*** 系统内部功能切换而导致的自动取消，例如从普通用户验证状态切换到管理员验证状态。
    Automatic cancellation due to the internal function switching of the system, 
    such as switching from the normal user verification state to the administrator verification state.
                <google translate> ****/

    detail_manual_cancel,                 
    /** The user manually completed the cancel function, such as pressing the cancel button
     * 用户手动操作的功能取消，例如操作了取消按钮
     ***/

    detail_operation_timeout_cancel,
    /** The user hasn't performed any operation for a long time
     * 用户操作超时(用户长时间未进行任何操作)，而导致的功能取消
     ***/

    /*************/
    detail_operation_kb_keys_pressed_toolong, 
    /*************/
    detail_operation_kb_keys_pressed_tooshort, 
};

/************************
* 按键板硬件说明：我的按键板上由数据键(数字0-9)和两个功能键(一个C键、一个OK键)组成。 并没有其他的功能键。
*          一般的按键板的数据键由数字键和一些字母键构成。我的按键板上的数据键也只有数字0-9, 没有英文字母键。
**************************/
#define Key_Code_0   '0'
#define Key_Code_1   '1'
#define Key_Code_2   '2'
#define Key_Code_3   '3'
#define Key_Code_4   '4'
#define Key_Code_5   '5'
#define Key_Code_6   '6'
#define Key_Code_7   '7'
#define Key_Code_8   '8'
#define Key_Code_9   '9'

#define Key_Code_ChangeMode   'C'  // 管理员/普通用户 模式切换键 
#define Key_Code_OK           'O'  // 确认键
#define Key_Code_Cancel       'A'  // 取消当前功能，例如开始注册后，按下此按键，可以取消注册。


enum e_inputdev_status{

    e_kb_enroll_success = 1,
    e_kb_enroll_fail,
      
    e_kb_auth_fail,
};


enum e_inputdev_results_detail{

    e_inputdev_results_no_detail = 0,
    e_kb_enroll_fail_pw_len_differ= 1,     //前后注册的密码长度不一致
    e_kb_enroll_fail_pw_content_differ= 1, //前后注册的密码内容不一致
    
};


enum inputmanager_rslt{
    e_inputdev_keyboard_enroll_success = 1,



};






#endif

